home *** CD-ROM | disk | FTP | other *** search
/ ASME's Mechanical Engine…ing Toolkit 1997 December / ASME's Mechanical Engineering Toolkit 1997 December.iso / c_lang / msgraph.lzh / MSGRAPH.ASM < prev    next >
Encoding:
Assembly Source File  |  1987-05-05  |  18.9 KB  |  750 lines

  1. SMALL    equ    0
  2. LARGE    equ    1
  3.  
  4. CODE_M    equ    LARGE            ; Set this according to the code
  5.                     ; model being used
  6.  
  7. DGROUP    group    NULL, _DATA
  8. NULL    segment para public 'BEGDATA'
  9. NULL    ENDS
  10.  
  11. _DATA    segment para public 'DATA'
  12.     extrn    _mode:word, _vidmseg:word, _bitspixl:word
  13.  
  14. psetjump dw    offset _TEXT:psetexit    ; holds address of point-plotting
  15.                     ; routine called by pset()
  16. count    dw    0            ; used by _line routine
  17. adj    dw    0            ; used by _fline routine
  18. _DATA    ends
  19.  
  20. _TEXT    segment para public 'CODE'
  21.     assume    cs:_TEXT, ds:DGROUP
  22.  
  23.     public    _pset, _init160, _setpjmp, _line, _fline, _doint
  24.  
  25. ; The following routine plots a point on the graphics screen in the
  26. ; specified color:
  27.  
  28.     ; returns bx=video offset, dh=mask value, dl=shifted color value
  29.     ; (see below); these values are used by the fline() function
  30.  
  31.     IF    CODE_M
  32. _pset    proc    far            ; pset(x, y, color)
  33.  
  34. xcoord    equ    [bp+6]            ; define parameter addressing
  35. ycoord    equ    [bp+8]
  36. pcolor    equ    [bp+10]
  37.  
  38.     ELSE
  39. _pset    proc    near
  40.  
  41. xcoord    equ    [bp+4]
  42. ycoord    equ    [bp+6]
  43. pcolor    equ    [bp+8]
  44.     ENDIF
  45.  
  46.     push    bp
  47.     mov    bp,sp
  48.  
  49.     jmp    [psetjump]        ; transfer control to appropriate
  50.                     ; point-plotting routine
  51.  
  52. psetexit:                ; control is transferred here if
  53.                     ; setpjmp() was never called or the
  54.                     ; video display is currently in a
  55.                     ; text mode
  56.     pop    bp
  57.     ret
  58.  
  59. pset320:                ; plot a point in 320x200 4-color mode
  60.     mov    bx,ycoord        ; get y coordinate
  61.     xor    dx,dx
  62.     shr    bx,1
  63.     rcr    dx,1            ; rotate low bit of bx into bit 13
  64.     ror    dx,1            ; of dx
  65.     ror    dx,1            ; dx=2000h if y is odd, =0 if y is even
  66.     mov    cl,4
  67.     shl    bx,cl            ; bx=(hi 7 bits of y coordinate) * 16
  68.     mov    ax,bx
  69.     shl    bx,1
  70.     shl    bx,1            ; bx=y coordinate * 64
  71.     add    bx,ax            ; bx=y coordinate * 80
  72.     add    bx,dx            ; bx=y coordinate * 80 + major offset
  73.     mov    ax,xcoord        ; get x coordinate
  74.     mov    cx,ax
  75.     shr    ax,1
  76.     shr    ax,1
  77.     add    bx,ax            ; bx now contains video memory offset
  78.     mov    dl,pcolor        ; get color
  79.     and    dl,3            ; only low 2 bits are used in 4-color
  80.                     ; mode
  81.     not    cl
  82.     and    cl,3            ; cl=inverted low 3 bits of x coord.
  83.                     ; this is used as a shift count to
  84.                     ; position the 2-bit color value
  85.                     ; within the proper byte in video RAM
  86.     add    cl,cl
  87.     shl    dl,cl
  88.     mov    dh,255-3
  89.     rol    dh,cl            ; dh=mask ("and") value, dl="or" value
  90.     push    es
  91.     mov    es,_vidmseg
  92.     and    es:[bx],dh
  93.     or    es:[bx],dl
  94.     pop    es
  95.     pop    bp
  96.     ret
  97.  
  98. pset640:                ; plot a point in 640x200 2-color mode
  99.     mov    bx,ycoord        ; get y coordinate
  100.     xor    dx,dx
  101.     shr    bx,1
  102.     rcr    dx,1
  103.     ror    dx,1
  104.     ror    dx,1            ; dx=2000h if y is odd, =0 if y is even
  105.     mov    cl,4
  106.     shl    bx,cl
  107.     mov    ax,bx
  108.     shl    bx,1
  109.     shl    bx,1
  110.     add    bx,ax
  111.     add    bx,dx
  112.     mov    ax,xcoord        ; get x coordinate
  113.     mov    cx,ax
  114.     shr    ax,1
  115.     shr    ax,1
  116.     shr    ax,1
  117.     add    bx,ax
  118.     mov    dl,pcolor        ; get color
  119.     and    dl,1            ; only low bit of color is significant
  120.     not    cl
  121.     and    cl,7
  122.     shl    dl,cl
  123.     mov    dh,254
  124.     rol    dh,cl
  125.     push    es
  126.     mov    es,_vidmseg
  127.     and    es:[bx],dh
  128.     or    es:[bx],dl
  129.     pop    es
  130.     pop    bp
  131.     ret
  132.  
  133. pset160:                ; plot a point in 160x100 16-color mode
  134.     mov    bx,ycoord        ; get y coordinate
  135.     mov    cx,bx
  136.     shl    cx,1
  137.     shl    cx,1
  138.     add    bx,cx            ; bx=y coordinate * 5
  139.     shl    bx,1
  140.     shl    bx,1
  141.     shl    bx,1
  142.     shl    bx,1
  143.     shl    bx,1            ; bx = y coordinate * 160
  144.     mov    ax,xcoord        ; get x coordinate
  145.     mov    cx,ax
  146.     and    ax,0fffeh        ; mask off low bit
  147.     add    bx,ax            ; bx now contains video memory offset
  148.     and    cx,1            ; low bit of x coordinate determines
  149.                     ; whether foreground or background
  150.                     ; attribute of character will be set
  151.     shl    cl,1
  152.     shl    cl,1            ; cl=0 for even x coordinates (left
  153.                     ; half of character position -
  154.                     ; foreground will be set), 4 for odd
  155.     mov    dl,pcolor        ; get color
  156.     and    dl,15            ; use only low 4 bits of color
  157.     shl    dl,cl
  158.     mov    dh,240
  159.     rol    dh,cl            ; dh=mask ("and") value, dl="or" value
  160.     push    es
  161.     mov    es,_vidmseg
  162.     mov    cl,221
  163.     mov    ch,es:[bx+1]        ; get current video RAM byte
  164.     and    ch,dh            ; modify it
  165.     or    ch,dl
  166.     mov    es:[bx],cx        ; store 221 character with new
  167.                     ; attribute in video memory
  168.     pop    es
  169.     pop    bp
  170.     ret
  171. _pset    endp
  172.  
  173. ; The following function performs the special CRT controller initialization
  174. ; for the 160x100 graphics modes:
  175.  
  176.     IF    CODE_M
  177. _init160 proc    far            ; init160()
  178.     ELSE
  179. _init160 proc    near
  180.     ENDIF
  181.  
  182.     mov    dx,3d8h
  183.     mov    al,9
  184.     out    dx,al            ; disable blinking attribute bit,
  185.                     ; enabling 16 background colors
  186.     mov    dx,3d4h            ; CRT controller's base I/O address
  187.     mov    al,4            ; register 4 = total vertical rows
  188.                     ; per frame
  189.     out    dx,al
  190.     inc    dx
  191.     mov    al,127            ; 127 rows total
  192.     out    dx,al
  193.     dec    dx
  194.     mov    al,6            ; register 6 = total displayed rows
  195.     out    dx,al
  196.     inc    dx
  197.     mov    al,100            ; 100 rows will be displayed. There is
  198.                     ; actually enough memory for 102 rows
  199.                     ; if your monitor can display the
  200.                     ; extra eight scan lines
  201.     out    dx,al
  202.     dec    dx
  203.     mov    al,7            ; VSYNC position register
  204.     out    dx,al
  205.     inc    dx
  206.     mov    al,112            ; VSYNC position - don't change
  207.     out    dx,al
  208.     dec    dx
  209.     mov    al,9            ; # of scan lines per row register
  210.     out    dx,al
  211.     inc    dx
  212.     mov    al,1            ; register 9 actually contains the
  213.                     ; number of scan lines per row minus
  214.                     ; 1, so for 2 scan lines per row a
  215.                     ; value of 1 is stored
  216.     out    dx,al
  217.     push    es
  218.     mov    ax,40h
  219.     mov    es,ax
  220.     mov    bx,_mode
  221.     mov    byte ptr es:[49h],bl    ; set BIOS current video mode byte
  222.     mov    es,_vidmseg
  223.     xor    di,di
  224.     mov    cx,16384
  225.     mov    ax,00ddh        ; set all characters to display
  226.                     ; character 221 with an attribute
  227.                     ; byte of zero (black foreground &
  228.                     ; background)
  229.     rep    stosw            ; clear screen
  230.     pop    es
  231.     ret
  232. _init160 endp
  233.  
  234.     ; The following routine stores in [psetjump] the address of the
  235.     ; point-plotting routine appropriate for the current video mode:
  236.  
  237.     IF    CODE_M
  238. _setpjmp proc    far            ; setpjmp(video_mode)
  239.  
  240. mode    equ    [bp+6]            ; define parameter addressing
  241.  
  242.     ELSE
  243. _setpjmp proc    near
  244.  
  245. mode    equ    [bp+4]
  246.     ENDIF
  247.  
  248.     push    bp
  249.     mov    bp,sp
  250.  
  251.     mov    ax,mode
  252.     shr    ax,1
  253.     cmp    ax,2            ; 320x200 b/w or color mode?
  254.     mov    bx,offset _TEXT:pset320
  255.     je    setpj1
  256.     cmp    ax,3            ; 640x200 b/w mode?
  257.     mov    bx,offset _TEXT:pset640
  258.     je    setpj1
  259.     cmp    ax,4            ; 160x100 b/w or color mode?
  260.     mov    bx,offset _TEXT:pset160
  261.     je    setpj1
  262.                     ; for non-graphics modes or unsupported
  263.                     ; modes, use "psetexit" routine which
  264.                     ; does nothing
  265.     mov    bx,offset _TEXT:psetexit
  266. setpj1:    mov    psetjump,bx        ; set address of point-plotting routine
  267.     pop    bp
  268.     ret
  269. _setpjmp endp
  270.  
  271. ;                    D  R  A  W     A     L  I  N  E
  272. ;
  273. ; This routine draws a line between points (x1,y1) and (x2,y2) with
  274. ; the given color. It supports whatever graphics modes are
  275. ; supported by the pset() routine and should work with any future
  276. ; graphics modes up to 65536x65536 resolution.
  277. ;
  278. ; The basic idea behind this function's operation is this: It computes
  279. ; "delta x" which equals the difference between x2 and x1, and "delta y"
  280. ; which equals the difference between y2 and y1. It starts drawing
  281. ; the line at coordinates (x1, y1) on the screen. It then adds 1/65536
  282. ; of delta x to the current x coordinate and 1/65536 of delta y to the
  283. ; current y coordinate to find the coordinates of the next point, draws the
  284. ; next point and repeats. The effect is that the slope of the line connecting
  285. ; any two adjacent points it draws is equal to the slope of the line
  286. ; connecting (x1, y1) and (x2, y2) and thus it draws a straight line from
  287. ; (x1, y1) to (x2, y2). By the time it has looped 65536 times it has added
  288. ; 65536/65536ths of delta x to x and 65536/65536ths of delta y to y and thus
  289. ; has reached the coordinates (x2, y2), the end of the line. Of course,
  290. ; modifications to this algorithm have been made so the routine doesn't
  291. ; actually plot 65536 dots for every line it draws; in fact, it doesn't
  292. ; ever draw a dot at a location where it has already drawn one.
  293. ;
  294. ; The CPU's registers are used as follows:
  295. ; DX - current x coordinate
  296. ; AX - current fraction of x coordinate in 65536ths
  297. ; CX - current y coordinate
  298. ; BX - current fraction of y coordinate in 65536ths
  299. ; SI - delta x (when x1 > x2, SI=absolute value of delta x)
  300. ; DI - delta y (always positive - see below)
  301. ;
  302.  
  303.     IF    CODE_M
  304. _line    proc    far            ; line(x1, y1, x2, y2, color)
  305.  
  306. x1    equ    [bp+6]            ; define parameter addressing
  307. y1    equ    [bp+8]
  308. x2    equ    [bp+10]
  309. y2    equ    [bp+12]
  310. color    equ    [bp+14]
  311.  
  312.     ELSE
  313. _line    proc    near
  314.  
  315. x1    equ    [bp+4]
  316. y1    equ    [bp+6]
  317. x2    equ    [bp+8]
  318. y2    equ    [bp+10]
  319. color    equ    [bp+12]
  320.     ENDIF
  321.  
  322.     push    bp
  323.     mov    bp,sp            ; set up parameter addressing on stack
  324.     push    si            ; must be preserved for MSC
  325.     push    di
  326.  
  327.     mov    count,0            ; initialize count for later
  328.     mov    cx,y1            ; get y1 coordinate
  329.     mov    di,y2            ; get y2 coordinate
  330.     sub    di,cx            ; di=delta y
  331.     jnc    line1
  332.     mov    ax,x1            ; if y1 > y2, swap x1 with x2 and
  333.                     ; y1 with y2 so that y1 is always
  334.                     ; less than y2
  335.     mov    bx,x2
  336.     mov    x1,bx
  337.     mov    x2,ax
  338.     mov    ax,y1
  339.     mov    bx,y2
  340.     mov    y1,bx
  341.     mov    y2,ax            ; swap x & y coords. so that
  342.                     ; x2<x1, y2>y1
  343.     mov    cx,bx            ; get y1 coordinate
  344.     mov    di,ax            ; get y2 coordinate again
  345.     sub    di,cx            ; di=delta y, is positive this time
  346. line1:    mov    bx,0ffffh        ; for later
  347.     mov    dx,x1            ; get x1 coordinate
  348.     mov    ax,0ffffh        ; for later
  349.     mov    si,x2            ; get x2 coordinate
  350.     sub    si,dx            ; si=delta x
  351.     jc    line10            ; if x1 > x2, draw the line with x
  352.                     ; decreasing from x1 to x2. Otherwise,
  353.                     ; draw the line with x increasing from
  354.                     ; x1 to x2. In either case, y
  355.                     ; increases from y1 to y2.
  356.     or    si,si            ; first, multiply delta x and delta y
  357.                     ; by 2 until the high bit of one or
  358.                     ; both is a 1 (normalize delta x and
  359.                     ; delta y)
  360.     js    line3            ; if either delta x or delta y is
  361.                     ; already normalized, skip the
  362.                     ; following code; count is already
  363.                     ; initialized to zero (which means
  364.                     ; an actual count of 65536 pixels will
  365.                     ; be drawn)
  366.     or    di,di
  367.     js    line3
  368.     shl    si,1
  369.     shl    di,1
  370.     mov    count,8000h        ; divide count by 2 each time dx and
  371.                     ; dy are doubled
  372. line2:    or    si,si
  373.     js    line3
  374.     or    di,di
  375.     js    line3
  376.     shl    si,1
  377.     shl    di,1
  378.     shr    count,1            ; divide count by 2
  379.     jnz    line2            ; continue unless count is now zero
  380.     mov    count,1            ; if count is zero, (x1, y1) and
  381.                     ; (x2, y2) must be the same point;
  382.                     ; set count equal to 1
  383.     jmp    line3
  384. line3a:    add    bx,di
  385.     jnc    line4
  386.     inc    cx
  387. line3:    push    ax            ; main loop
  388.     push    bx
  389.     push    di            ; save registers that will be destroyed
  390.                     ; by the pset() routine
  391.     push    color            ; pass color to pset()
  392.     push    cx            ; pass y coordinate and
  393.     push    dx            ; x coordinate to pset() and also
  394.                     ; save them on the stack
  395.     call    _pset            ; draw next point on the line
  396.     pop    dx            ; restore dx & cx from stack (pset()
  397.     pop    cx            ; doesn't modify the parameters it
  398.                     ; gets on the stack so it is safe to
  399.                     ; do this)
  400.     add    sp,2            ; adjust stack
  401.     pop    di            ; restore registers
  402.     pop    bx
  403.     pop    ax
  404. line4:    dec    count
  405.     jz    line5            ; if count is zero, exit
  406.     add    ax,si            ; otherwise, adjust x & y coordinates
  407.                     ; for next point on the line
  408.     jnc    line3a            ; line3a loops back to line4 if
  409.                     ; neither the x nor the y coordinate
  410.                     ; was changed by the adjustment to
  411.                     ; save the time of redrawing a dot at
  412.                     ; the same place that one was just
  413.                     ; drawn
  414.     inc    dx            ; if ax overflowed, add carry into dx
  415.     add    bx,di            ; adjust y coordinate
  416.     adc    cx,0            ; add in carry, if any
  417.     jmp    line3
  418. line5:    pop    di
  419.     pop    si
  420.     pop    bp
  421.     ret
  422.  
  423. line10:                    ; This is the same code as is at
  424.                     ; line1 above, except that it
  425.                     ; subtracts the si register from the
  426.                     ; current x coordinate rather than
  427.                     ; adding it; this routine is used if
  428.                     ; x1 > x2 while the code at line1 is
  429.                     ; used if x1 < x2. No matter what,
  430.                     ; y1 is always less than or equal
  431.                     ; to y2.
  432.     neg    si            ; now both si and di are positive
  433.                     ; (actually unsigned 16-bit integers)
  434.     or    si,si
  435.     js    line13
  436.     or    di,di
  437.     js    line13
  438.     shl    si,1
  439.     shl    di,1
  440.     mov    count,8000h
  441. line12:    or    si,si
  442.     js    line13
  443.     or    di,di
  444.     js    line13
  445.     shl    si,1
  446.     shl    di,1
  447.     shr    count,1
  448.     jnz    line12
  449.     mov    count,1
  450.     jmp    line13
  451.  
  452. line13a:add    bx,di
  453.     jnc    line14
  454.     inc    cx
  455. line13:    push    ax
  456.     push    bx
  457.     push    di            ; save registers destroyed by pset()
  458.     push    color            ; pass color,
  459.     push    cx            ; y coordinate and
  460.     push    dx            ; x coordinate to pset()
  461.     call    _pset
  462.     pop    dx
  463.     pop    cx
  464.     add    sp,2
  465.     pop    di
  466.     pop    bx
  467.     pop    ax
  468. line14:    dec    count
  469.     jz    line15
  470.     sub    ax,si            ; subtract x coordinate adjustment
  471.     jnc    line13a
  472.     dec    dx            ; if there was a borrow from the MSB
  473.                     ; of x coordinate, decrement it by one
  474.     add    bx,di            ; now adjust the y coordinate
  475.     adc    cx,0
  476.     jmp    line13
  477.  
  478. line15:    pop    di
  479.     pop    si
  480.     pop    bp
  481.     ret
  482. _line    endp
  483.  
  484. ;                   F  A  S  T      L  I  N  E  -  D  R  A  W
  485. ;
  486. ; This routine operates on the same basic principle as the line-drawing
  487. ; function above, but differs in that it manipulates video RAM contents
  488. ; directly instead of going through the pset() routine. It is roughly
  489. ; five times as fast as the routine above, but only works in the 320x200
  490. ; and 640x200 graphics modes. There are four sections of code in this
  491. ; function, only one of which will actually be executed on a particular
  492. ; call to the routine:
  493. ; lin0  - used if x1 >= x2 and delta y >= delta x
  494. ; lin10 - used if x1 >= x2 and delta y < delta x
  495. ; lin20 - used if x1 < x2 and delta y >= delta x
  496. ; lin30 - used if x1 < x2 and delta y < delta x
  497. ;
  498. ; Hopefully soon I will have time to clean this code up a little
  499. ; and document it better, but for the meantime, at least it runs real
  500. ; fast.
  501.  
  502.     IF    CODE_M
  503. _fline    proc    far        ; fline()
  504.     ELSE
  505. _fline    proc    near
  506.     ENDIF
  507.  
  508. ;x1    equ    [bp+4]        ; these five parameters were defined in
  509. ;y1    equ    [bp+6]        ; the line() routine above and are the
  510. ;x2    equ    [bp+8]        ; same for this routine; they are commented
  511. ;y2    equ    [bp+10]        ; out because MASM does not allow redefinition
  512. ;color    equ    [bp+12]        ; of equ's
  513.  
  514.     push    bp
  515.     mov    bp,sp        ; set up parameter addressing on stack
  516.     push    si        ; must be preserved for MSC
  517.     push    di
  518.  
  519. lin0c:    push    color
  520.     push    y1
  521.     push    x1
  522.     call    _pset        ; pset() returns bx=video memory offset,
  523.                 ; dh=mask value, dl=color value of the
  524.                 ; plotted point
  525.     add    sp,6        ; remove parameters
  526.     mov    di,bx        ; place video offset in di
  527.     mov    cx,y2
  528.     sub    cx,y1        ; compute delta y
  529.     jnc    lin0b
  530.     mov    ax,x1        ; if y1 > y2, swap x1 with x2 and y1 with y2
  531.     mov    bx,x2        ; so that y1 is always less than y2
  532.     mov    x1,bx
  533.     mov    x2,ax
  534.     mov    ax,y1
  535.     mov    bx,y2
  536.     mov    y1,bx
  537.     mov    y2,ax
  538.     jmp    lin0c        ; go back and recompute delta y, etc.
  539.  
  540. lin0b:    push    es
  541.     mov    es,_vidmseg
  542.     push    dx
  543.     mov    dx,x2
  544.     sub    dx,x1        ; get delta x in dx
  545.     jnc    lin0d
  546.     neg    dx        ; if delta x < 0, use routine at lin20
  547.     jmp    lin20
  548. lin0d:    cmp    dx,cx        ; is delta x > delta y?
  549.     ja     lin10        ; if yes, use routine at lin10
  550.     jb    lin0
  551.     or    cx,cx        ; if delta x and delta y are both zero, exit
  552.     jz    lin0e
  553.     mov    ax,0ffffh    ; otherwise, delta x = delta y; set up ax
  554.                 ; and bypass divide
  555.     jmp    short lin0a
  556.  
  557. lin0e:    pop    dx        ; remove dx from stack
  558.     jmp    flindone    ; exit
  559.  
  560. lin0:    xor    ax,ax        ; dx:ax contains delta x * 65536
  561.     div    cx        ; compute 65536 * delta x / delta y
  562. lin0a:    mov    adj,ax        ; save 65536 * delta x / delta y
  563.     pop    dx
  564.     mov    si,2000h
  565.     test    byte ptr y1,1    ; is y1 even?
  566.     jz    lin1        ; if so, 2000h is initial video memory
  567.                 ; address adjust
  568.     mov    si,0e050h    ; if not, e050h is
  569. lin1:    mov    bx,8000h    ; initialize 65536ths counter for x
  570.     mov    bp,adj        ; due to lack of registers, we're forced to
  571.                 ; use bp to hold x adjust value
  572.  
  573. lin2:                ; main loop
  574.     add    di,si        ; add 2000h or e050h alternately to video
  575.                 ; memory offset
  576.     xor    si,0c050h    ; toggle 2000h to e050h and back
  577.     add    bx,bp        ; adjust x
  578.     jc    lin4        ; if low word of x coordinate overflowed,
  579.                 ; do lin4
  580. lin3:    mov    al,es:[di]    ; get current video memory byte
  581.     and    al,dh        ; modify it
  582.     or    al,dl
  583.     stosb            ; store new byte in video RAM to plot point
  584.                 ; on line
  585.     dec    di
  586.     loop    lin2
  587.     jmp    flindone
  588. lin4:                ; here we adjust the mask ("and") and "or"
  589.                 ; values used to modify video memory contents
  590.                 ; to reflect the change in the x coordinate
  591.     mov    ax,cx
  592.     mov    cx,_bitspixl
  593. lin5:    ror    dl,cl
  594.     ror    dh,cl
  595.     mov    cx,ax
  596.     jc    lin3        ; if a bit of 1 was shifted through the carry
  597.                 ; flag when rotating dh, then di doesn't need
  598.                 ; to be adjusted
  599.     inc    di        ; adjust di to point to next location to the
  600.                 ; right in video memory
  601.     jmp    short lin3
  602.  
  603. lin10:
  604.     xor    ax,ax
  605.     xchg    cx,dx        ; place delta x in cx and delta y in dx
  606.     div    cx
  607.     mov    adj,ax        ; put 65536 * delta x / delta y in "adj"
  608.     pop    dx
  609.     mov    si,2000h
  610.     test    byte ptr y1,1
  611.     jz    lin11
  612.     mov    si,0e050h
  613. lin11:    mov    bx,8000h
  614.     mov    bp,adj        ; place y adjust in bp
  615.     mov    ax,cx
  616.     mov    cx,_bitspixl
  617.     jmp    lin12
  618. lin12a:    inc    di
  619.     jmp    lin13
  620. lin12:    ror    dl,cl
  621.     ror    dh,cl
  622.     jnc    lin12a
  623. lin13:    add    bx,bp        ; adjust y
  624.     jc    lin14
  625. lin13a:    mov    ch,es:[di]
  626.     and    ch,dh
  627.     or    ch,dl
  628.     mov    es:[di],ch
  629.     dec    ax
  630.     jnz    lin12
  631.     jmp    flindone
  632. lin14:    add    di,si        ; add 2000h or e050h alternately to video memory offset
  633.     xor    si,0c050h    ; toggle 2000h to e050h and back
  634.     jmp    lin13a
  635.  
  636. lin20:    cmp    dx,cx        ; is delta x > delta y?
  637.     ja    lin30
  638.     jb    lin20b
  639.     mov    ax,0ffffh    ; if delta x = delta y, set up ax and bypass divide
  640.     jmp    lin20a
  641. lin20b:    xor    ax,ax
  642.     div    cx
  643. lin20a:    mov    adj,ax        ; put 65536 * delta x / delta y in "adj"
  644.     pop    dx
  645.     mov    si,2000h
  646.     test    byte ptr y1,1    ; is y1 even?
  647.     jz    lin21        ; if so, 2000h is initial address adjust
  648.     mov    si,0e050h    ; if not, this is
  649. lin21:    mov    bx,8000h    ; initialize 65536ths counter for x
  650.     mov    bp,adj        ; place x adjust in bp
  651. lin22:    add    di,si        ; add 2000h or e050h alternately to video memory offset
  652.     xor    si,0c050h    ; toggle 2000h to e050h and back
  653.     add    bx,bp        ; adjust x
  654.     jc    lin24
  655. lin23:    mov    al,es:[di]
  656.     and    al,dh
  657.     or    al,dl
  658.     stosb
  659.     dec    di
  660.     loop    lin22
  661.     jmp    flindone
  662. lin24:    mov    ax,cx
  663.     mov    cx,_bitspixl
  664. lin25:    rol    dl,cl
  665.     rol    dh,cl
  666.     mov    cx,ax
  667.     jc    lin23        ; dec instruction doesn't affect carry flag
  668.     dec    di
  669.     jmp    lin23
  670.  
  671. lin30:    xor    ax,ax
  672.     xchg    cx,dx        ; place delta x in cx and delta y in dx
  673.     div    cx
  674.     mov    adj,ax        ; put 65536 * delta x / delta y in "adj"
  675.     pop    dx
  676.     mov    si,2000h
  677.     test    byte ptr y1,1
  678.     jz    lin31
  679.     mov    si,0e050h
  680. lin31:    mov    bx,8000h
  681.     mov    bp,adj        ; place y adjust in bp
  682.     mov    ax,cx
  683.     mov    cx,_bitspixl
  684.     jmp    lin32
  685. lin32a:    dec    di
  686.     jmp    lin33
  687. lin32:    rol    dl,cl
  688.     rol    dh,cl
  689.     jnc    lin32a
  690. lin33:    add    bx,bp        ; adjust y
  691.     jc    lin34
  692. lin33a:    mov    ch,es:[di]
  693.     and    ch,dh
  694.     or    ch,dl
  695.     mov    es:[di],ch
  696.     dec    ax
  697.     jnz    lin32
  698.     jmp    flindone
  699. lin34:    add    di,si        ; add 2000h or e050h alternately to video
  700.                 ; memory offset
  701.     xor    si,0c050h    ; toggle 2000h to e050h and back
  702.     jmp    lin33a
  703. flindone:
  704.     pop    es
  705.     pop    di
  706.     pop    si
  707.     pop    bp
  708.     ret
  709. _fline    endp
  710.  
  711. ; The function below calls the specified interrupt number after loading
  712. ; the specified value into the AX register.
  713.  
  714.     IF    CODE_M
  715. _doint    proc    far            ; doint(intno, r_ax)
  716.  
  717. intno    equ    [bp+6]            ; define parameter addressing
  718. r_ax    equ    [bp+8]
  719.  
  720.     ELSE
  721. _doint    proc    near
  722.  
  723. intno    equ    [bp+4]
  724. r_ax    equ    [bp+6]
  725.     ENDIF
  726.  
  727.     push    bp
  728.     mov    bp,sp
  729.  
  730.     push    es
  731.     xor    ax,ax
  732.     mov    es,ax
  733.     mov    bl,intno        ; put interrupt # in al
  734.     xor    bh,bh
  735.     shl    bx,1
  736.     shl    bx,1            ; es:[bx] now contains interrupt vector
  737.     mov    ax,r_ax            ; load variable "ax" into ax
  738.     pushf                ; set up stack for iret instruction
  739.                     ; that the interrupt routine will
  740.                     ; perform
  741.     call    dword ptr es:[bx]
  742.     pop    es
  743.  
  744.     pop    bp
  745.     ret
  746. _doint    endp
  747.  
  748. _TEXT    ends
  749.     end
  750.